import tkinter as tk
from tkinter import messagebox
import random

# 全局变量
data = []
size = 5
end = '111111111'
good = 0.01
sex = 0.85
ag = 0.02
max_generations = 100
fitness_history = []

# 测试字符串
def test_str(value):
    return all(c == '1' for c in value)

# 适应度函数
def ok(v):
    return v in end

# 初始化种群
def start():
    global data
    data = []
    for i in range(size):
        gene = ''.join('1' if random.random() > 0.5 else '0' for _ in range(len(end)))
        data.append(gene)
    show_text.insert(tk.END, f"初始化种群: {data}\n")
    show_text.see(tk.END)

# 遗传算法
def heredity():
    global data, max_generations
    if len(data) < 2:
        show_text.insert(tk.END, "由于种群少于2个人，重新初始化种群！\n")
        start()
    # 适应值排序
    data.sort(key=lambda x: len([v for v in x if ok(v)]), reverse=True)
    # 记录适应度
    best_fitness = len([v for v in data[0] if ok(v)])
    fitness_history.append(best_fitness)
    # 判断是否找到基因序列
    if data[0] == end:
        show_text.insert(tk.END, f"已经找到基因：{data[0]}\n")
        return
    elif max_generations < 1:
        show_text.insert(tk.END, f"目前最优秀的基因是：{data[0]}\n")
        return
    max_generations -= 1
    show_text.insert(tk.END, f"还剩{max_generations}次进化机会\n")
    show_text.see(tk.END)
    # 新生儿童基因数据库
    news = []
    is_l = len(data)
    # 选择出精英个体
    good_i = int(good * is_l)
    news.extend(data[:good_i])
    # 选择需要遗传的个体
    sex_i = int(sex * is_l)
    sum_fitness = sum(range(is_l, 0, -1))
    arr = [sum(range(is_l - i, 0, -1)) for i in range(is_l)]
    sexs = []
    for _ in range(sex_i):
        rand = random.random() * sum_fitness
        for a in range(is_l):
            if rand < arr[a]:
                sexs.append(data[a])
                break
    # 开始交叉基因片段
    len_gene = len(end)
    for _ in range(size):
        new_x = random.randint(0, len(sexs) - 1)
        new_y = random.randint(0, len(sexs) - 1)
        xs = list(sexs[new_x])
        ys = list(sexs[new_y])
        xy = []
        for j in range(len_gene):
            xy_ag = random.random()
            if random.random() > 0.5:
                if xy_ag < ag:
                    xy_gene = '0' if xs[j] == '1' else '1'
                else:
                    xy_gene = xs[j]
            else:
                if xy_ag < ag:
                    if ys[j] == '1':
                        xy_gene = '0' if random.random() > 0.7 else '1'
                    else:
                        xy_gene = '1' if random.random() > 0.2 else '0'
                else:
                    xy_gene = ys[j]
            xy.append(xy_gene)
        news.append(''.join(xy))
    data = news

# 设置参数
def set_params():
    global size, end, good, sex, ag, max_generations, fitness_history
    try:
        new_end = end_entry.get()
        if not test_str(new_end):
            messagebox.showerror("错误", "最终基因只能包含 1。")
            return
        end = new_end
        size = int(size_entry.get())
        good = float(good_entry.get())
        sex = float(sex_entry.get())
        ag = float(ag_entry.get())
        max_generations = int(max_entry.get())
        fitness_history = []
        show_text.insert(tk.END, f"参数设置更新：最终基因={end}，种群规模={size}，精英率={good}，交叉率={sex}，变异率={ag}，最大迭代次数={max_generations}\n")
    except ValueError:
        messagebox.showerror("错误", "请输入有效的数字。")

# 创建主窗口
root = tk.Tk()
root.title("二进制遗传算法")

# 定义字体
font_style = ("Arial", 16)

# 参数输入框
tk.Label(root, text="最终基因：", font=font_style).grid(row=0, column=0,sticky="e")
end_entry = tk.Entry(root, font=font_style)
end_entry.insert(0, end)
end_entry.grid(row=0, column=1,columnspan=2,sticky="w")

tk.Label(root, text="种群规模：", font=font_style).grid(row=1, column=0,sticky="e")
size_entry = tk.Entry(root, font=font_style)
size_entry.insert(0, size)
size_entry.grid(row=1, column=1,columnspan=2,sticky="w")

tk.Label(root, text="精英率：", font=font_style).grid(row=2, column=0,sticky="e")
good_entry = tk.Entry(root, font=font_style)
good_entry.insert(0, good)
good_entry.grid(row=2, column=1,columnspan=2,sticky="w")

tk.Label(root, text="交叉率：", font=font_style).grid(row=3, column=0,sticky="e")
sex_entry = tk.Entry(root, font=font_style)
sex_entry.insert(0, sex)
sex_entry.grid(row=3, column=1,columnspan=2,sticky="w")

tk.Label(root, text="变异率：", font=font_style).grid(row=4, column=0,sticky="e")
ag_entry = tk.Entry(root, font=font_style)
ag_entry.insert(0, ag)
ag_entry.grid(row=4, column=1,columnspan=2,sticky="w")

tk.Label(root, text="最大迭代次数：", font=font_style).grid(row=5, column=0,sticky="e")
max_entry = tk.Entry(root, font=font_style)
max_entry.insert(0, max_generations)
max_entry.grid(row=5, column=1,columnspan=2,sticky="w",pady=10)

# 设置参数按钮
set_params_button = tk.Button(root, text="设置参数", command=set_params, font=font_style)
set_params_button.grid(row=6, column=0, pady=10)

# 初始化种群按钮
start_button = tk.Button(root, text="初始化种群", command=start, font=font_style)
start_button.grid(row=6, column=1,pady=10)
# 开始遗传按钮
heredity_button = tk.Button(root, text="遗传一次", command=heredity, font=font_style)
heredity_button.grid(row=6, column=2,pady=10)

# 显示文本框
show_text = tk.Text(root, height=10, width=60, font=font_style)
show_text.grid(row=8, column=0, columnspan=3, pady=10)

# 运行主循环
root.mainloop()